﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;

namespace HN.WxPayApiV3Partner.Model
{
    public static class V3Request
    {
        /// <summary>
        /// V3请求
        /// </summary>
        /// <param name="urlMethod">接口地址类</param>
        /// <param name="bodyString">body请求参数字符串</param>
        /// <param name="dicQuery">query请求参数集合</param>
        /// <param name="pathValue">path请求参数值</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="WxPayException"></exception>
        public static string HttpRequest(
            UrlMethod urlMethod,
            string bodyString = "",
            Dictionary<string, Object> dicQuery = null,
            string pathValue = "")
        {
            if (urlMethod == null)
                throw new ArgumentNullException("method");
            if (dicQuery != null)
            {
                urlMethod.url += "?";
                foreach (KeyValuePair<string, object> pair in dicQuery)
                {
                    if (pair.Value == null)
                    {
                        throw new WxPayException("dicQuery内部含有值为null的字段!");
                    }
                    urlMethod.url += pair.Key + "=" + pair.Value + "&";
                }
                urlMethod.url = urlMethod.url.Trim('&');

            }
            if (!string.IsNullOrEmpty(urlMethod.path) && pathValue != "")
            {
                urlMethod.url = urlMethod.url.Replace(urlMethod.path, pathValue);
            }
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlMethod.url);
            request.Method = urlMethod.method;
            request.ContentType = "application/json;charset=UTF-8";
            request.UserAgent = "bjhnkj.cn/WebRequest";
            request.Accept = "application/json";
            request.Headers.Add("Authorization", GetAuthorization(urlMethod, bodyString));
            if (urlMethod.method != "GET")
            {
                byte[] paramJsonBytes;
                paramJsonBytes = Encoding.UTF8.GetBytes(bodyString);
                request.ContentLength = paramJsonBytes.Length;
                Stream writer;
                try
                {
                    writer = request.GetRequestStream();
                }
                catch (Exception)
                {
                    writer = null;
                    Console.Write("连接服务器失败!");
                }
                writer.Write(paramJsonBytes, 0, paramJsonBytes.Length);
                writer.Close();
            }
            HttpWebResponse response;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException ex)
            {
                response = ex.Response as HttpWebResponse;
            }
            Stream resStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(resStream);
            string text = reader.ReadToEnd();
            return text;

        }
        /// <summary>
        /// 获取HTTP头的授权信息
        /// </summary>
        /// <param name="urlMethod">基础地址方法</param>
        /// <param name="bodyString">body字符串</param>
        /// <returns></returns>
        private static string GetAuthorization(UrlMethod urlMethod, string bodyString)
        {
            var uri = new Uri(urlMethod.url);
            string urlPath = uri.PathAndQuery;
            string nonce = Guid.NewGuid().ToString();
            var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
            string method = string.IsNullOrEmpty(urlMethod.method) ? "" : urlMethod.method;
            string message = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n", method, urlPath, timestamp, nonce, bodyString);
            string signString = Sign(message, V3Const.privateKey);
            string authorzationString = string.Format("WECHATPAY2-SHA256-RSA2048 mchid=\"{0}\",nonce_str=\"{1}\",timestamp=\"{2}\",serial_no=\"{3}\",signature=\"{4}\"",
                V3Const.sp_mchid,
                nonce,
                timestamp,
                V3Const.serialNo,
                signString
                );
            return authorzationString;
        }

        private static string Sign(string message, string privateKey)
        {
            byte[] keyData = Convert.FromBase64String(privateKey);
            using (CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob))
            using (RSACng rsa = new RSACng(cngKey))
            {
                byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
                return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
            }
        }
    }
}
